在我们使用传统的 Spring MVC + Spring + Mybatis 整合开发时,通常采用的是使用xml配置 + Java注解混合式的开发,即跟业务相关的使用Java注解,配置相关的使用xml文件。这就造成了我们需要写大量的xml配置代码。
在微服务兴起后,Spring Boot 和 Spring Cloud 等微服务框架都摒弃了xml配置文件的配置方式,大量使用Java注解来进行开发。
Spring 注解驱动开发分为Spring 容器相关,Spring 原理,Spring MVC。
首先从Spring容器说起,Spring容器的两个重要概念就是控制反转和依赖注入。Spring将所有的组件都放在了容器中,组件中的关系通过容器来进行自动装配。那如何使用注解的形式进行容器的注入和自动装配?
1 组件注册
1.1 注入Bean:@Configuration、@Bean
1.1.1 xml配置方式
最原始的配置方式,需要将注入的Bean全都配置到Spring的配置文件中。
首先,我们有一个bean对象。
1 | public class Persion { |
要想将这个Bean对象注入到Spring容器中,如下:
一、在Spring的配置文件 applicationContext.xml
配置文件中配置bean:
1 | <bean id="person" class="com.enhao.spring.annotation.bean.Person"> |
二、测试
1 | public static void main(String[] args) { |
使用
ClassPathXmlApplicationContext
读取配置文件。
1.1.2 注解驱动配置方式
注解驱动开发将不再使用applicationContext.xml
xml配置文件,使用Java类取代配置文件。
一、配置类等同于之前的配置文件。在配置类上使用@Configuration
注解,表明这是一个配置类。
注入对象时,使用@Bean
注解,给容器中注册一个Bean。方法返回值为Bean的类型,方法名为Bean的id。也可以使用@Bean
注解的value属性设置id。
1 | // 配置类 == 配置文件 |
@Bean
注解,等价于1.1中的<bean></bean>
配置方式。
二、测试:
1 | public static void main(String[] args) { |
使用
AnnotationConfigApplicationContext
读取配置类。不再是ClassPathXmlApplicationContext
了。
1.2 包扫描:@ComponentScan
1.2.1 xml + 注解混合配置方式
在Java5引入注解的特性后,诞生了xml + 注解混合式开发的方式。
一、在Spring的配置文件 applicationContext.xml
配置文件中开启注解扫描:
1 | <context:component-scan base-package="com.enhao.spring.annotation.service"/> |
主要标注了
@controller
、@Service
、@Repository
、@Component
注解中任意一个,都会被扫描自动注入容器中。
二、在需要注入的Bean类上添加@Component
注解:
1 | "personService") ( |
三、测试:
1 | public static void main(String[] args) { |
1.2.2 注解驱动配置方式
一、注解驱动的配置包扫描的方式是直接在配置类上使用@ComponentScan
注解即可。
1 |
|
二、在需要注入的Bean类上添加@controller
、@Service
、@Repository
、@Component
注解中任意一个即可。
@ComponentScan
的属性:
value
:指定要扫描的包。excludeFilters
:指定扫描的时候按照什么规则排除哪些组件。值是Filter[]
。@Filter
注解:type
属性表示指定排除的规则:按照注解排除,按照AspectJ表达式排除,按照给定的类型排除、按照自定义排除和按照正则排除;classes
属性表示根据排除规则需要排除的类。
includeFilters
:指定扫描的时候只需要包含哪些组件。值为Filter[]
。注意:如果使用includeFilters
,必须关闭默认的过滤规则(默认过滤规则是包含所有),将useDefaultFilters
设置为false。
1 | "com.enhao.spring.annotation", excludeFilters = { (value = |
FilterType.ANNOTATION
使用按照注解排除的规则,排除标注了@Controller
和@Service
注解的Bean。
1 | "com.enhao.spring.annotation", useDefaultFilters = false, includeFilters = { (value = |
使用按照注解的规则,只包含使用了
@Controller
注解的Bean。注意:使用
includeFilters
时,必须将useDefaultFilters
的值设置为false。
1 | "com.enhao.spring.annotation", useDefaultFilters = false, includeFilters = { (value = |
FilterType.ASSIGNABLE_TYPE
包含给定的类型,这里会包含是PersonService
类型的Bean。
由于java8引入了重复注解的概念(具体可以查看Java8新特性),所有可以写多个@ComponentScan
注解来指定不同的规则。
如果是Java8以前的版本,可以使用@ComponentScans
注解,该注解里可以写多个@ComponentScan
注解。
1.3 作用域:@Scope
1.3.1 @Scope和@Bean一起使用
Spring 的Bean默认都是单实例的。可用使用@Scope
来指定Bean的作用域。
通过@Scope
注解的value
属性来指定Bean的作用域,值有四种:singleton
(默认值)、prototype
、request
、session
。
1 |
|
等同于
<bean scope=""></bean>
注意:
在默认单实例时,在Spring容器启动时就会调用方法将Bean对象放到容器中。以后每次获取都是直接从容器中获取的。
在多实例时,Spring 容器启动时并不会区创建多实例Bean的对象。多实例Bean对象是在调用的时候才放到容器中的,而且是每调用一次就向容器中放入一个对象。
1.3.2 @Scope和@Component一起使用
在使用包扫描的时候,如果要指定Bean的作用域,可以和@Component
、@Service
、@Repository
、@Controller
等注解一起使用,使用方式和上面一样。
1.4 懒加载:@Lazy
懒加载只针对于单实例的Bean。因为单实例的Bean是在容器启动的时候就加载的。
懒加载:容器启动的时候不创建对象。在第一次使用(获取)Bean的时候创建对象,并初始化。
1.4.1 @Lazy和@Bean一起使用
1 |
|
1.4.2 @Lazy和@Component一起使用
在使用包扫描的时候,如果要指定Bean的懒加载,可以和@Component
、@Service
、@Repository
、@Controller
等注解一起使用,使用方式和上面一样。
1.5 条件注解:@Conditional
作用:按照一定的条件进行判断,满足条件给容器注册Bean。
@Conditional
注解的value
属性是继承了Condition
的Class对象。因此需要实现Condition
接口。
例子:判断当前的系统,如果是linux系统,则创建Persion3对象。如果是Windows系统则创建Person4对象。
1 | // 判断是否是windows系统 |
1.6 快速注册组件:@Import
1.6.1 直接导入配置类或普通类
@Import注解支持导入配置类,也支持导入普通的java类,并将其声明成一个bean。
1 |
|
注入Bean的id默认是组件的全类名。
1.6.2 使用ImportSelector
使用ImportSelector
导入选择器接口。接口里的selectImports
方法的返回值返回的是需要导入的组件的全类名数组。
一、自定义导入选择器:
1 | public class MyImportSelector implements ImportSelector { |
二、在@Import
注解中引入自定义的导入选择器。
1 |
|
1.6.3 使用ImportBeanDefinitionRegistrar
使用ImportBeanDefinitionRegistrar
接口,实现registerBeanDefinitions
方法,在容器中自己添加组件。
一、自定义一个ImportBeanDefinitionRegistrar
实现类:
1 | public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { |
二、在@Import
中使用
1 |
|
1.7 使用FactoryBean注册组件
一、自定义一个FactoryBean实现类:
1 | public class ColorFactoryBean implements FactoryBean<Color> { |
二、在配置类中配置工厂类Bean:
1 |
|
默认获取到的是工厂Bean调用
GetObject
创建的对象,这里是Color
。要获取工厂Bean的本身,我们需要给id前面加一个
&
标识。